package com.fjec.market.service.impl;

import com.aliyuncs.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjec.common.enums.EnumOrderStatus;
import com.fjec.common.enums.EnumSysCode;
import com.fjec.common.exception.BizException;
import com.fjec.common.jxls.BreakfastExcel;
import com.fjec.common.protocol.JsonResult;
import com.fjec.common.setting.Setting;
import com.fjec.common.shiro.AccountInfo;
import com.fjec.common.util.BizUtil;
import com.fjec.common.util.DateUtil;
import com.fjec.common.util.JsonUtil;
import com.fjec.common.util.SequenceIdGenerator;
import com.fjec.common.view.RpcReturnPage;
import com.fjec.market.entity.*;
import com.fjec.market.feign.ActivityClient;
import com.fjec.market.feign.BaseClient;
import com.fjec.market.feign.PaidClient;
import com.fjec.market.feign.UserClient;
import com.fjec.market.mapper.BizPhysicalOrderMapper;
import com.fjec.market.mapper.BizShoppingCartMapper;
import com.fjec.market.rabbitmq.provider.OrderTimeoutProvider;
import com.fjec.market.rabbitmq.provider.PreparePayProvider;
import com.fjec.market.rabbitmq.provider.SysMsgProvider;
import com.fjec.market.service.*;
import com.fjec.market.view.OrderItem;
import com.fjec.market.view.SubOrderDetailVO;
import com.fjec.market.view.SubOrderVO;
import com.google.common.base.Joiner;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.common.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.awt.*;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 041.实物订单表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-09-21
 */
@Slf4j
@Service
public class BizPhysicalOrderServiceImpl extends ServiceImpl<BizPhysicalOrderMapper, BizPhysicalOrder> implements IBizPhysicalOrderService {

    @Value("${fjec.market.order.remind.deliver.time}")
    private Integer remindTime;

    @Value("${fjec.market.order.auto.sign.time}")
    private Integer autoSignDays;

    @Value("${fjec.market.order.auto.refund.time}")
    private Integer autoRefundHours;

    @Resource
    private BizPhysicalOrderMapper mapper;

    @Resource
    private IInfoSkuService infoSkuService;

    @Resource
    private IBizSubPhysicalOrderService bizSubPhysicalOrderService;

    @Resource
    private IBizLogisticalDeliveryService bizLogisticalDeliveryService;

    @Resource
    private BizShoppingCartMapper bizShoppingCartMapper;

    @Resource
    private SequenceIdGenerator idGenerator;

    @Resource
    private OrderTimeoutProvider orderTimeoutProvider;

    @Resource
    private BaseClient baseClient;

    @Resource
    private UserClient userClient;

    @Resource
    private ActivityClient activityClient;

    @Resource
    private SysMsgProvider sysMsgProvider;

    @Autowired
    private PreparePayProvider preparePayProvider;

    @Resource
    private IInfoYsepayRegisterService infoYsepayRegisterService;

    @Resource
    private IBizDepositOperateRecordService bizDepositOperateRecordService;

    @Resource
    private IInfoFarmerService infoFarmerService;

    @Resource
    private IInfoBusinessService infoBusinessService;

    @Resource
    private IBizServOrderService bizServOrderService;

    @Resource
    private IBizSubServOrderService bizSubServOrderService;

    @Autowired
    private PaidClient paidClient;

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public JsonResult saveOrder(String addressName, String addressPhone, String address,
                                Integer totalPrice, Integer orderType, List<OrderItem> productList) {
        // 获取系统参数
        Map<String, Object> settingMap = baseClient.getSysSetting();
        if (settingMap == null) {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_3001.getCode())
                    .message(EnumSysCode.ERR_3001.getMsg())
                    .build();
        }
        Setting setting = new Setting(settingMap);

        String guid = BizUtil.guid();
        // 整理商品信息
        List<Long> skuIdList = new ArrayList<>();
        // 商铺订单Map
        Map<String, BizPhysicalOrder> shopOrderMap = new HashMap<>();
        // 商铺商品Map
        Map<Long, String> skuShopMap = new HashMap<>();
        // 购物车Id列表
        List<Long> scIdList = new ArrayList<>();
        // 订单Id列表
        List<Long> orderIdList = new ArrayList<>();
        // 创建时间
        LocalDateTime now = DateUtil.nowLdt();
        // 按照商户分割订单，并创建订单
        for (OrderItem item : productList) {
            // 整理购物车Id，后面用来删除已生成订单的购物车数据
            if (item.getCartId() != null && item.getCartId() != 0) {
                scIdList.add(item.getCartId());
            }
            // 加入skuId
            skuIdList.add(item.getProductId());
            // 用busiType和busiId创建唯一标识一个商铺，每个商铺1个订单
            String key = item.getBusiType().toString() + item.getBusiId().toString();
            // 保存商品和商铺关系
            skuShopMap.put(item.getProductId(), key);
            // 处理未处理过的订单数据
            if (!shopOrderMap.containsKey(key)) {
                BizPhysicalOrder order = new BizPhysicalOrder();
                order.setId(idGenerator.nextId());
                orderIdList.add(order.getId());
                order.setUserId(AccountInfo.getUserId());
                // add by huangjian: 增加买家店铺名或微信昵称
                if (AccountInfo.getBusiType() == 1) {
                    order.setBuyerShopName(AccountInfo.getWxNickName());
                } else {
                    order.setBuyerShopName(AccountInfo.getShopName());
                }
                // end
                order.setSubOrderNum(productList.size());
                order.setShopType(item.getBusiType());
                order.setShopId(item.getBusiId());
                order.setOrderType(orderType);
                order.setAmount(0);
                order.setRealAmount(0);
                order.setUseDisc(0);// 无优惠
                order.setOrderStatus(EnumOrderStatus.UNPAID.getCode());
//                order.setOrderStatus(EnumOrderStatus.PAID.getCode());
                order.setGuid(guid);
                order.setRemark(item.getRemark());
                order.setCreateTime(now);
                if (orderType.intValue() == 1) {
                    order.setCommission(new BigDecimal(setting.getFruitsRetailCommission()));
                } else if (orderType.intValue() == 2) {
                    order.setCommission(new BigDecimal(setting.getFruitsBatchCommission()));
                }
                Map<String, Object> receiveInfoMap = new HashMap<>();
                receiveInfoMap.put("contact", addressName);
                receiveInfoMap.put("phone", addressPhone);
                receiveInfoMap.put("address", address);
                order.setReceiveInfo(receiveInfoMap);
                order.setGuaranteeStatus(0); // 银盛担保交易同步状态
                shopOrderMap.put(key, order);
            }
        }
        // 查询商品sku数据
        List<Map<String, Object>> mapList = infoSkuService.getSkuInfoByIdList(skuIdList);
        // 整理子订单数据
        List<BizSubPhysicalOrder> subOrderList = new ArrayList<>();
        for (Map<String, Object> map : mapList) {
            Long skuId = MapUtils.getLong(map, "SkuId");
            String shopName = MapUtils.getString(map, "ShopName");
            Long shopNum = MapUtils.getLong(map, "ShopNum");
            String linkMan = MapUtils.getString(map, "LinkMan");
            String linkPhone = MapUtils.getString(map, "LinkPhone");
            String compHeadPic = MapUtils.getString(map, "CompHeadPic");
            Integer delFlag = MapUtils.getInteger(map, "DelFlag");
            Integer saleable = MapUtils.getInteger(map, "Saleable");
            String skuTitle = MapUtils.getString(map, "SkuTitle");
            String spuDesc = MapUtils.getString(map, "SpuDesc");
            String retailSpec = MapUtils.getString(map, "RetailSpec");
            Integer retailPrice = MapUtils.getInteger(map, "RetailPrice");
            String wholesaleUnit = MapUtils.getString(map, "WholesaleUnit");
            Integer wholesalePrice = MapUtils.getInteger(map, "WholesalePrice");
            Integer markCode = MapUtils.getInteger(map, "MarkCode");
            Integer depoStatus = MapUtils.getInteger(map, "DepoStatus");
            // 校验店铺是否已交保证金
            if (depoStatus != 1) {
                return JsonResult.failure()
                        .code(EnumSysCode.ERR_0040.getCode())
                        .message(EnumSysCode.ERR_0040.getMsg())
                        .build();
            }
            // check 商品是否可以销售
            if (delFlag == 1 || saleable == 0) {
                return JsonResult.failure()
                        .code(EnumSysCode.ERR_0040.getCode())
                        .message(EnumSysCode.ERR_0040.getMsg())
                        .build();
            }
            // 自己不能买自己的商品
            if (AccountInfo.isAuthenticated()) {
                Integer busiType = AccountInfo.getBusiType();
                Long busiId = AccountInfo.getBusiId();
                int skuBusiType = MapUtils.getIntValue(map, "BuisType", -1);
                long skuBusiId = MapUtils.getLong(map, "BusiId", -1L);
                if (busiType != null && busiId != null && skuBusiType == busiType.intValue()
                        && skuBusiId == busiId.longValue()) {
                    return JsonResult.failure()
                            .code(EnumSysCode.ERR_3019.getCode())
                            .message(EnumSysCode.ERR_3019.getMsg())
                            .build();
                }
            }
            // 获取第一张图片作为商品快照
            String strPics = MapUtils.getString(map, "SpuPics");
            if (!Strings.isNullOrEmpty(strPics)) {
                List<String> picList = JsonUtil.jsonToObject(strPics, List.class);
                if (picList != null && !picList.isEmpty()) {
                    strPics = picList.get(0);
                } else {
                    strPics = "";
                }
            } else {
                strPics = "";
            }
            // 创建子订单
            BizSubPhysicalOrder subOrder = new BizSubPhysicalOrder();
            subOrder.setMarkCode(markCode);
            if (orderType.intValue() == 1) {
                // 1 =水果零售订单
                for (OrderItem item : productList) {
                    if (skuId.longValue() == item.getProductId().longValue()) {
                        int num = item.getProductNum();
                        Integer amount = retailPrice * num;
                        subOrder.setNum(num);
                        subOrder.setAmount(amount);
                        subOrder.setRealAmount(amount);
                        break;
                    }
                }
            } else if (orderType.intValue() == 2) {
                // 2=水果批量采购订单（批量采购时，订单详细表的原价格、实际购买价格、购买数量均为0）
                for (OrderItem item : productList) {
                    if (skuId.longValue() == item.getProductId().longValue()) {
                        subOrder.setBulkPurcNum(item.getBulkPurcNum());
                        subOrder.setAmount(item.getBulkPurcAmout());
                        subOrder.setRealAmount(item.getBulkPurcAmout());
                        break;
                    }
                }
            } else {
                // 3=知识付费 暂时没有
            }
            subOrder.setId(idGenerator.nextId());
            subOrder.setSkuId(skuId);
            subOrder.setOrderStatus(EnumOrderStatus.UNPAID.getCode());
            subOrder.setPostage(0);
            subOrder.setUseDisc(0);// 无优惠
            subOrder.setCreateTime(now);
            // sku快照
            Map<String, Object> snapshotMap = new HashMap<>();
            snapshotMap.put("skuTitle", skuTitle);
            snapshotMap.put("spuDesc", spuDesc);
            snapshotMap.put("strPics", strPics);
            snapshotMap.put("retailSpec", retailSpec);
            snapshotMap.put("retailPrice", retailPrice);
            snapshotMap.put("wholesaleUnit", wholesaleUnit);
            snapshotMap.put("wholesalePrice", wholesalePrice);
            subOrder.setSkuSnapshot(snapshotMap);
            // 根据skuId获取shopKey
            String shopKey = skuShopMap.get(subOrder.getSkuId());
            // 通过shopKey取得订单
            BizPhysicalOrder order = shopOrderMap.get(shopKey);
            subOrder.setOrderId(order.getId());
            // 计算订单总金额
            order.setAmount(order.getAmount() + subOrder.getAmount());
            order.setRealAmount(order.getRealAmount() + subOrder.getRealAmount());
            // 保存商铺快照到订单
            if (order.getShopInfo() == null) {
                Map<String, Object> shopInfoMap = new HashMap<>();
                shopInfoMap.put("shopName", shopName);
                shopInfoMap.put("compHeadPic", compHeadPic);
                shopInfoMap.put("shopNum", shopNum);
                shopInfoMap.put("linkMan", linkMan);
                shopInfoMap.put("linkPhone", linkPhone);
                // 保存ShopNum
                order.setShopNum(shopNum);
                // 保存商铺快照
                order.setShopInfo(shopInfoMap);
            }

            subOrderList.add(subOrder);
        }
        // 保存订单
        for (BizPhysicalOrder order : shopOrderMap.values()) {
            if (order.getRealAmount() > Integer.parseInt(setting.getMaxOrderAmount())) {
                return JsonResult
                        .failure()
                        .code(EnumSysCode.ERR_3026.getCode())
                        .message(String.format("单笔支付金额不能超过%d元", Integer.parseInt(setting.getMaxOrderAmount()) / 100))
                        .build();
            }

            if (order.getRealAmount() < 100) {
                return JsonResult
                        .failure()
                        .code(EnumSysCode.ERR_3026.getCode())
                        .message("单笔支付金额不能低于1元")
                        .build();
            }
            mapper.insert(order);
        }

        // 保存子订单
        bizSubPhysicalOrderService.saveBatch(subOrderList);
        // 如果有购物车删除购物车
        if (!scIdList.isEmpty()) {
            UpdateWrapper<BizShoppingCart> updateWrapper = new UpdateWrapper<>();
            updateWrapper.in("Id", scIdList);
            BizShoppingCart scEntity = new BizShoppingCart();
            scEntity.setDelFlag(1);
            scEntity.setUpdateTime(DateUtil.nowLdt());
            bizShoppingCartMapper.update(scEntity, updateWrapper);
        }

        // 发送prepare pay消息给paid服务
        BizPhysicalOrder order = shopOrderMap.values().stream().findFirst().get();
        Long orderId = order.getId();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String shopDate = now.format(formatter);
        // outTradeNo
        String outTradeNo = shopDate + orderId;
        // subOpenId
        String subOpenId = AccountInfo.getOpenId();
        // subject 商品名称
        BizSubPhysicalOrder subOrder = subOrderList.get(0);
        String subject = MapUtils.getString(subOrder.getSkuSnapshot(), "skuTitle");
        // totalAmount
        String totalAmount = String.valueOf(order.getRealAmount().doubleValue() / 100);
        // todo: sellerId and sellerName
        Long busiId = order.getShopId();
        Integer busiType = order.getShopType();
        InfoYsepayRegister infoYsepayRegister = infoYsepayRegisterService.getOne(
                new QueryWrapper<InfoYsepayRegister>()
                        .eq("BusiType", busiType)
                        .eq("BusiId", busiId));
        String sellerId = infoYsepayRegister.getUserCode();
        String sellerName = infoYsepayRegister.getCustName();
        Integer paymentType = 2;
        // 发送prepare pay消息给paid服务
        preparePayProvider.sendPreparePay(subOpenId, outTradeNo, shopDate, subject, totalAmount, sellerId, sellerName, paymentType);
        // 发送定时任务，2小时后检查订单是否已付款，未付款则删除订单
        orderTimeoutProvider.sendDelayMsgForOrderTimeout(orderIdList);

        Map<String, Object> result = new HashMap<>();
        result.put("orderId", orderId);
        return JsonResult.success().data(result).build();
    }

    /**
     * 订单查询
     *
     * @param page
     * @param status 1=全部
     *               2=待付款
     *               3=待发货
     *               4=待收货
     *               5=待评价
     *               6=投诉
     *               7=投诉处理中
     *               8=投诉已处理
     * @return
     */
    @Override
    public JsonResult listForOrderStatus(Page page, Integer status) {
        Long userId = AccountInfo.getUserId();
        Page<Map<String, Object>> resultPage = mapper.getOrderByUserIdAndStatus(page, userId, status);
        List<Object> resultList = new ArrayList<>();
        for (Map<String, Object> orderMap : resultPage.getRecords()) {
            // 获取商铺快照和商品快照
            String strShopInfo = MapUtils.getString(orderMap, "ShopInfo");
            String strSkuSnapshot = MapUtils.getString(orderMap, "SkuSnapshot");
            // 整理属性
            SubOrderVO view = new SubOrderVO();
            view.setOrderId(MapUtils.getString(orderMap, "OrderId"));
            view.setSubOrderId(MapUtils.getString(orderMap, "SubOrderId"));
            view.setGuid(MapUtils.getString(orderMap, "Guid"));
            view.setShopType(MapUtils.getInteger(orderMap, "ShopType"));
            view.setShopId(MapUtils.getString(orderMap, "ShopId"));
            view.setSkuId(MapUtils.getString(orderMap, "SkuId"));
            view.setRealAmount(MapUtils.getInteger(orderMap, "RealAmount"));
            view.setRemark(MapUtils.getString(orderMap, "Remark"));
            view.setSubOrderNum(MapUtils.getInteger(orderMap, "SubOrderNum"));
            int orderType = MapUtils.getIntValue(orderMap, "OrderType");
            view.setOrderType(orderType);
            if (orderType == 1) {
                view.setNum(MapUtils.getInteger(orderMap, "Num"));
            } else if (orderType == 2) {
                view.setBulkPurcNum(MapUtils.getString(orderMap, "BulkPurcNum"));
            }
            if (!Strings.isNullOrEmpty(strShopInfo)) {
                Map<String, Object> shopInfoMap = JsonUtil.jsonToMap(strShopInfo);
                view.setShopName(MapUtils.getString(shopInfoMap, "shopName"));
                view.setCompHeadPic(MapUtils.getString(shopInfoMap, "compHeadPic"));
            }
            if (!Strings.isNullOrEmpty(strSkuSnapshot)) {
                Map<String, Object> skuSnapshotMap = JsonUtil.jsonToMap(strSkuSnapshot);
                view.setSkuTitle(MapUtils.getString(skuSnapshotMap, "skuTitle"));
                view.setSkuPic(MapUtils.getString(skuSnapshotMap, "strPics"));
                view.setRetailSpec(MapUtils.getString(skuSnapshotMap, "retailSpec"));
                view.setRetailPrice(MapUtils.getInteger(skuSnapshotMap, "retailPrice"));
                view.setWholesaleUnit(MapUtils.getString(skuSnapshotMap, "wholesaleUnit"));
                view.setWholesalePrice(MapUtils.getInteger(skuSnapshotMap, "wholesalePrice"));
            }
            /**
             * 数据库状态 1=未付款 2=已付款 3=已发货 4=已签收
             */
            // 整理状态 投诉优先
            int complaintStatus = MapUtils.getIntValue(orderMap, "ComplaintStatus");
            view.setComplaintStatus(complaintStatus);
            if (complaintStatus > 0) {
                if (complaintStatus == 1) {
                    view.setOrderStatus(7);
                    view.setOrderStatusStr("投诉处理中");
                } else {
                    view.setOrderStatus(8);
                    view.setOrderStatusStr("投诉已处理");
                }
            } else {
                Long ratingId = MapUtils.getLong(orderMap, "RatingId");
                Integer orderStatus = MapUtils.getInteger(orderMap, "OrderStatus");
                switch (orderStatus) {
                    case 1:
                        view.setOrderStatus(2);
                        view.setOrderStatusStr("待付款");
                        break;
                    case 2:
                        view.setOrderStatus(3);
                        view.setOrderStatusStr("待发货");
                        break;
                    case 3:
                        view.setOrderStatus(4);
                        view.setOrderStatusStr("待收货");
                        break;
                    case 4:
                        if (ratingId == null) {
                            view.setOrderStatus(5);
                            view.setOrderStatusStr("待评价");
                        } else {
                            view.setOrderStatus(6);
                            view.setOrderStatusStr("已完成");
                        }
                        break;
                    case 5:
                        view.setOrderStatus(9);
                        view.setOrderStatusStr("已关闭");
                        break;
                    case 6:
                    case 7:
                        view.setOrderStatus(10);
                        view.setOrderStatusStr("发货超时退款");
                        break;

                }
            }
            // 评价Id
            view.setRatingId(MapUtils.getString(orderMap, "RatingId"));
            // 加入数组
            resultList.add(view);
        }
        return JsonResult.success()
                .data(resultList)
                .total(resultPage.getTotal())
                .build();
    }

    /**
     * @param page
     * @param status
     * @return
     */
    @Override
    public JsonResult getSaleOrderList(Page page, Integer status) {
//        Long userId = AccountInfo.getUserId();
        Page<Map<String, Object>> resultPage = mapper.getOrderByBusiIdAndBusiType(page, AccountInfo.getBusiId(), AccountInfo.getBusiType(), status);
        List<Object> resultList = new ArrayList<>();
        for (Map<String, Object> orderMap : resultPage.getRecords()) {
            // 获取商铺快照和商品快照
            String strShopInfo = MapUtils.getString(orderMap, "ShopInfo");
            String strSkuSnapshot = MapUtils.getString(orderMap, "SkuSnapshot");
            String strReceiveInfo = MapUtils.getString(orderMap, "ReceiveInfo");
            // 整理属性
            SubOrderVO view = new SubOrderVO();
            view.setOrderId(MapUtils.getString(orderMap, "OrderId"));
            view.setSubOrderId(MapUtils.getString(orderMap, "SubOrderId"));
            view.setGuid(MapUtils.getString(orderMap, "Guid"));
            view.setShopType(MapUtils.getInteger(orderMap, "ShopType"));
            view.setShopId(MapUtils.getString(orderMap, "ShopId"));
            view.setSkuId(MapUtils.getString(orderMap, "SkuId"));
            view.setRealAmount(MapUtils.getInteger(orderMap, "RealAmount"));
            view.setRemark(MapUtils.getString(orderMap, "Remark"));
            view.setSubOrderNum(MapUtils.getInteger(orderMap, "SubOrderNum"));
            int orderType = MapUtils.getIntValue(orderMap, "OrderType");
            view.setOrderType(orderType);
            if (orderType == 1) {
                view.setNum(MapUtils.getInteger(orderMap, "Num"));
            } else if (orderType == 2) {
                view.setBulkPurcNum(MapUtils.getString(orderMap, "BulkPurcNum"));
            }
            if (!Strings.isNullOrEmpty(strShopInfo)) {
                Map<String, Object> shopInfoMap = JsonUtil.jsonToMap(strShopInfo);
                view.setShopName(MapUtils.getString(shopInfoMap, "shopName"));
                view.setCompHeadPic(MapUtils.getString(shopInfoMap, "compHeadPic"));
            }
            if (!Strings.isNullOrEmpty(strSkuSnapshot)) {
                Map<String, Object> skuSnapshotMap = JsonUtil.jsonToMap(strSkuSnapshot);
                view.setSkuTitle(MapUtils.getString(skuSnapshotMap, "skuTitle"));
                view.setSkuPic(MapUtils.getString(skuSnapshotMap, "strPics"));
                view.setRetailSpec(MapUtils.getString(skuSnapshotMap, "retailSpec"));
                view.setRetailPrice(MapUtils.getInteger(skuSnapshotMap, "retailPrice"));
                view.setWholesaleUnit(MapUtils.getString(skuSnapshotMap, "wholesaleUnit"));
                view.setWholesalePrice(MapUtils.getInteger(skuSnapshotMap, "wholesalePrice"));
            }
            // 收货地址
            if (!Strings.isNullOrEmpty(strReceiveInfo)) {
                Map<String, Object> receiveInfoMap = JsonUtil.jsonToMap(strReceiveInfo);
                view.setContact(MapUtils.getString(receiveInfoMap, "contact"));
                view.setPhone(MapUtils.getString(receiveInfoMap, "phone"));
                view.setAddress(MapUtils.getString(receiveInfoMap, "address"));
            }
            /**
             * 数据库状态 1=未付款 2=已付款 3=已发货 4=已签收
             */
            // 整理状态 投诉优先
            int complaintStatus = MapUtils.getIntValue(orderMap, "ComplaintStatus");
            view.setComplaintStatus(complaintStatus);
            if (complaintStatus > 0) {
                if (complaintStatus == 1) {
                    view.setOrderStatus(7);
                    view.setOrderStatusStr("投诉处理中");
                } else {
                    view.setOrderStatus(8);
                    view.setOrderStatusStr("投诉已处理");
                }
            } else {
                Long ratingId = MapUtils.getLong(orderMap, "RatingId");
                Integer orderStatus = MapUtils.getInteger(orderMap, "OrderStatus");
                switch (orderStatus) {
                    case 1:
                        view.setOrderStatus(2);
                        view.setOrderStatusStr("待付款");
                        break;
                    case 2:
                        view.setOrderStatus(3);
                        view.setOrderStatusStr("待发货");
                        break;
                    case 3:
                        view.setOrderStatus(4);
                        view.setOrderStatusStr("待收货");
                        break;
                    case 4:
                        if (ratingId == null) {
                            view.setOrderStatus(5);
                            view.setOrderStatusStr("待评价");
                        } else {
                            view.setOrderStatus(6);
                            view.setOrderStatusStr("已完成");
                        }
                        break;
                    case 6:
                    case 7:
                        view.setOrderStatus(10);
                        view.setOrderStatusStr("发货超时退款");
                        break;
                }
            }
            // 评价Id
            view.setRatingId(MapUtils.getString(orderMap, "RatingId"));
            // 加入数组
            resultList.add(view);
        }
        return JsonResult.success()
                .data(resultList)
                .total(resultPage.getTotal())
                .build();
    }

    @Override
    public JsonResult subOrderDetail(Long subOrderId) {
        Map<String, Object> orderMap = mapper.getSubOrderDetailById(subOrderId);
        // 获取商铺快照和商品快照
        String strShopInfo = MapUtils.getString(orderMap, "ShopInfo");
        String strSkuSnapshot = MapUtils.getString(orderMap, "SkuSnapshot");
        String strReceiveInfo = MapUtils.getString(orderMap, "ReceiveInfo");
        // 整理属性
        SubOrderDetailVO view = new SubOrderDetailVO();
        view.setOrderId(MapUtils.getString(orderMap, "OrderId"));
        view.setSubOrderId(MapUtils.getString(orderMap, "SubOrderId"));
        view.setGuid(MapUtils.getString(orderMap, "Guid"));
        view.setSkuId(MapUtils.getString(orderMap, "SkuId"));
        view.setRealAmount(MapUtils.getInteger(orderMap, "RealAmount"));
        view.setRemark(MapUtils.getString(orderMap, "Remark"));
        view.setSubOrderNum(MapUtils.getInteger(orderMap, "SubOrderNum"));
        // 判断订单时买入还是卖出
        int busiType = MapUtils.getIntValue(orderMap, "ShopType");
        view.setShopType(busiType);
        long busiId = MapUtils.getLongValue(orderMap, "ShopId");
        view.setShopId(String.valueOf(busiId));
        // 判断订单时买入还是卖出
        if (busiId == AccountInfo.getBusiId().longValue()
                && busiType == AccountInfo.getBusiType().intValue()) {
            // 卖出
            view.setSaleOrBuy(2);
        } else {
            // 买入
            view.setSaleOrBuy(1);
        }
        // 订单类型
        int orderType = MapUtils.getIntValue(orderMap, "OrderType");
        view.setOrderType(orderType);
        if (orderType == 1) {
            view.setNum(MapUtils.getInteger(orderMap, "Num"));
        } else if (orderType == 2) {
            view.setBulkPurcNum(MapUtils.getString(orderMap, "BulkPurcNum"));
        }
        if (!Strings.isNullOrEmpty(strShopInfo)) {
            Map<String, Object> shopInfoMap = JsonUtil.jsonToMap(strShopInfo);
            view.setShopName(MapUtils.getString(shopInfoMap, "shopName"));
            view.setCompHeadPic(MapUtils.getString(shopInfoMap, "compHeadPic"));
        }
        if (!Strings.isNullOrEmpty(strSkuSnapshot)) {
            Map<String, Object> skuSnapshotMap = JsonUtil.jsonToMap(strSkuSnapshot);
            view.setSkuTitle(MapUtils.getString(skuSnapshotMap, "skuTitle"));
            view.setSkuPic(MapUtils.getString(skuSnapshotMap, "strPics"));
            view.setRetailSpec(MapUtils.getString(skuSnapshotMap, "retailSpec"));
            view.setRetailPrice(MapUtils.getInteger(skuSnapshotMap, "retailPrice"));
            view.setWholesaleUnit(MapUtils.getString(skuSnapshotMap, "wholesaleUnit"));
            view.setWholesalePrice(MapUtils.getInteger(skuSnapshotMap, "wholesalePrice"));
        }
        // 收货地址
        if (!Strings.isNullOrEmpty(strReceiveInfo)) {
            Map<String, Object> receiveInfoMap = JsonUtil.jsonToMap(strReceiveInfo);
            view.setContact(MapUtils.getString(receiveInfoMap, "contact"));
            view.setPhone(MapUtils.getString(receiveInfoMap, "phone"));
            view.setAddress(MapUtils.getString(receiveInfoMap, "address"));
        }
        /**
         * 数据库状态 1=未付款 2=已付款 3=已发货 4=已签收
         */
        // 整理状态
        Long ratingId = MapUtils.getLong(orderMap, "RatingId");
        int orderStatus = MapUtils.getIntValue(orderMap, "OrderStatus");
        view.setOrderStatus(orderStatus);
        int complaintStatus = MapUtils.getIntValue(orderMap, "ComplaintStatus");
        view.setComplaintStatus(complaintStatus);
        if (complaintStatus > 0) {
            if (complaintStatus == 1) {
                view.setOrderStatus(7);
                view.setOrderStatusStr("投诉处理中");
            } else {
                view.setOrderStatus(8);
                view.setOrderStatusStr("投诉已处理");
            }
        } else {
            switch (orderStatus) {
                case 1:
                    view.setOrderStatus(2);
                    view.setOrderStatusStr("待付款");
                    break;
                case 2:
                    view.setOrderStatus(3);
                    view.setOrderStatusStr("待发货");
                    break;
                case 3:
                    view.setOrderStatus(4);
                    view.setOrderStatusStr("待收货");
                    break;
                case 4:
                    if (ratingId == null) {
                        view.setOrderStatus(5);
                        view.setOrderStatusStr("待评价");
                    } else {
                        view.setOrderStatus(6);
                        view.setOrderStatusStr("已完成");
                    }
                    break;
                case 5:
                    view.setOrderStatus(9);
                    view.setOrderStatusStr("已关闭");
                    break;
                case 6:
                case 7:
                    view.setOrderStatus(10);
                    view.setOrderStatusStr("发货超时退款");
                    break;
            }
        }

        // 订单时间
        view.setDeliveredTime(MapUtils.getString(orderMap, "DeliveredTimeStr"));
        view.setPaidTime(MapUtils.getString(orderMap, "PaidTimeStr"));
        view.setSignedTime(MapUtils.getString(orderMap, "SignedTimeStr"));
        // 物流信息
        view.setDeliType(MapUtils.getInteger(orderMap, "DeliType"));
        view.setDeliName(MapUtils.getString(orderMap, "DeliName"));
        view.setDeliNum(MapUtils.getString(orderMap, "DeliNum"));
        view.setDeliPerson(MapUtils.getString(orderMap, "DeliPerson"));
        view.setDeliPersonPhone(MapUtils.getString(orderMap, "DeliPersonPhone"));
        // 订单评价
        view.setRatingId(MapUtils.getString(orderMap, "RatingId"));
        int quality = MapUtils.getIntValue(orderMap, "QualityRating", 0);
        int speed = MapUtils.getIntValue(orderMap, "SpeedRating", 0);
        int logistics = MapUtils.getIntValue(orderMap, "LogisticsRating", 0);
        view.setQualityRating(quality / 100d);
        view.setSpeedRating(speed / 100d);
        view.setLogisticsRating(logistics / 100d);
        view.setSkuComment(MapUtils.getString(orderMap, "SkuComment"));
        // 投诉按钮处理q
        if (orderStatus == 4) {
//            int complaintStatus = MapUtils.getIntValue(orderMap, "ComplaintStatus");
            switch (complaintStatus) {
                case 0:
                    // 显示投诉按钮
                    Object objSignedTime = MapUtils.getObject(orderMap, "SignedTime");
                    if (objSignedTime != null) {
                        Timestamp tt = (Timestamp) objSignedTime;
                        long hours = DateUtil.betweenDate(DateUtil.nowDate(), new Date(tt.getTime()), ChronoUnit.HOURS);
                        if (hours <= 48) {
                            // 可以投诉
                            view.setComplaintBtn(1);
                        } else {
                            // 投诉已过期
                            view.setComplaintBtn(2);
                        }
                    }
                    break;
                case 1:
                    // 显示投诉状态 投诉中
                    view.setComplaintBtn(3);
                    view.setHandleResultStr("处理中");
                    break;
                case 2:
                case 3:
                    // 处理已完成
                    view.setComplaintBtn(4);
                    view.setHandleResultStr("已处理");
                    break;
            }
        } else {
            view.setComplaintBtn(0);
        }
        // 投诉信息
        view.setCompId(MapUtils.getString(orderMap, "CompId"));
        view.setCompTime(MapUtils.getString(orderMap, "CompTime"));
        view.setCompContext(MapUtils.getString(orderMap, "Context"));
        view.setHandleTime(MapUtils.getString(orderMap, "HandleTime"));
        int handleResult = MapUtils.getIntValue(orderMap, "HandleResult");
        view.setHandleResult(handleResult);
        view.setAdvice(MapUtils.getString(orderMap, "Advice"));
        return JsonResult.success()
                .data(view)
                .build();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public JsonResult subOrderDelivery(Long id, Integer deliType, Long deliId,
                                       String compName, String orderNum, String person, String phone) {
        // check子订单是否存在
        BizSubPhysicalOrder subOrder = bizSubPhysicalOrderService.getById(id);
        if (subOrder == null || subOrder.getDelFlag() == 1) {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_0041.getCode())
                    .message(EnumSysCode.ERR_0041.getMsg())
                    .build();
        }
        // check子订单状态是否为已支付
        if (subOrder.getOrderStatus() != 2) {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_0042.getCode())
                    .message(EnumSysCode.ERR_0042.getMsg())
                    .build();
        }
        BizLogisticalDelivery delivery = new BizLogisticalDelivery();
        delivery.setId(idGenerator.nextId());
        delivery.setSubOrderId(id);
        delivery.setCreateTime(DateUtil.nowLdt());
        // 数据库 1=物流 2=快递
        if (deliType == 1) {
            // 物流
            delivery.setDeliPerson(person);
            delivery.setDeliPersonPhone(phone);
            delivery.setCompType(1);
        } else if (deliType == 2) {
            // 快递
            delivery.setDeliNum(orderNum);
            delivery.setCompId(deliId);
            delivery.setCompName(compName);
            delivery.setCompType(2);
        } else {
            // 其他
            delivery.setDeliNum(orderNum);
            delivery.setCompName(compName);
            delivery.setCompType(2);
        }
        // 保存物流信息
        bizLogisticalDeliveryService.save(delivery);
        // 修改订单状态
        LocalDateTime now = DateUtil.nowLdt();
        subOrder.setOrderStatus(3);
        subOrder.setDeliveredTime(now);
        subOrder.setUpdateTime(now);
        bizSubPhysicalOrderService.updateById(subOrder);
        subOrder = bizSubPhysicalOrderService.getById(subOrder.getId());
        Map<String, Object> resultMap = new HashMap<>();
        if (subOrder.getOrderStatus().intValue() == 3) {
            resultMap.put("orderStatus", 4);
            resultMap.put("orderStatusStr", "待收货");
        } else {
            throw new BizException(EnumSysCode.ERR_3003.getCode(), EnumSysCode.ERR_3003.getMsg());
        }

        // 提示买家已发货 add by huangjian
        BizPhysicalOrder order = this.getById(subOrder.getOrderId());
        Long buyerUserId = order.getUserId();
        Map<String, Object> buyerOpenId = userClient.getOpenIdByUserId(buyerUserId);
        String openId = MapUtils.getString(buyerOpenId, "openId");
        Map<String, String> bizData = new HashMap<>();
        bizData.put("openId", openId);
        String shopName = MapUtils.getString(order.getShopInfo(), "shopName");
        bizData.put("shopName", shopName);
        String spuName = MapUtils.getString(subOrder.getSkuSnapshot(), "skuTitle");
        if (subOrder.getNum() == null)
            bizData.put("spuList", spuName);
        else
            bizData.put("spuList", spuName + "*" + subOrder.getNum());
        bizData.put("deliComp", compName);
        bizData.put("deliNum", orderNum);
        bizData.put("notification", "订单已发货，请注意查收");

        String title = "订单发货提醒";
        String content = String.format("订单编号%s，您购买的%s，卖家已发货。", subOrder.getId(), spuName);
        sysMsgProvider.sendSysMessage(1, 9009, bizData, buyerUserId, title, content, 0L);

        return JsonResult.success()
                .data(resultMap)
                .code(EnumSysCode.MSG_6005.getCode())
                .message(EnumSysCode.MSG_6005.getMsg())
                .build();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public JsonResult subOrderSigned(Long id) {
        // check子订单是否存在
        BizSubPhysicalOrder subOrder = bizSubPhysicalOrderService.getById(id);
        if (subOrder == null || subOrder.getDelFlag() == 1) {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_0041.getCode())
                    .message(EnumSysCode.ERR_0041.getMsg())
                    .build();
        }
        // check订单状态是否为已发货
        if (subOrder.getOrderStatus() != 3) {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_0042.getCode())
                    .message(EnumSysCode.ERR_0042.getMsg())
                    .build();
        }
        // 修改子订单状态
        LocalDateTime now = DateUtil.nowLdt();
        subOrder.setOrderStatus(4);
        subOrder.setSignedTime(now);
        subOrder.setUpdateTime(now);
        bizSubPhysicalOrderService.updateById(subOrder);
        // 获取子订单状态并转换
        subOrder = bizSubPhysicalOrderService.getById(subOrder.getId());
        Map<String, Object> resultMap = new HashMap<>();
        if (subOrder.getOrderStatus().intValue() == 4) {
            resultMap.put("orderStatus", 5);
            resultMap.put("orderStatusStr", "待评价");
        } else {
            throw new BizException(EnumSysCode.ERR_3003.getCode(), EnumSysCode.ERR_3003.getMsg());
        }

        // 发送送消息给卖家提示买家已签收订单
        Map<String, String> bizData = new HashMap<>();
        Long sellerUserId = this.getSellerUserIdByOrderId(subOrder.getOrderId());
        Map<String, Object> sellerOpenId = userClient.getOpenIdByUserId(sellerUserId);
        String openId = MapUtils.getString(sellerOpenId, "openId");
        bizData.put("openId", openId);
        String subOrderId = String.valueOf(subOrder.getId());
        bizData.put("orderId", subOrderId);
        String buyer = AccountInfo.getShopName();
        if (Strings.isNullOrEmpty(buyer))
            buyer = AccountInfo.getWxNickName();
        bizData.put("buyer", buyer);
        String spuName = MapUtils.getString(subOrder.getSkuSnapshot(), "skuTitle");
        bizData.put("spuName", spuName);

        String title = "确认收货通知";
        String userName = AccountInfo.getShopName();
        if (Strings.isNullOrEmpty(userName))
            userName = AccountInfo.getWxNickName();
        String content = String.format("订单编号%s，用户%s已确认收货。", subOrderId, userName);
        sysMsgProvider.sendSysMessage(1, 9003, bizData, sellerUserId, title, content, 0L);
        // end发送送消息给卖家提示买家已签收订单

        return JsonResult.success()
                .data(resultMap)
                .code(EnumSysCode.MSG_6006.getCode())
                .message(EnumSysCode.MSG_6006.getMsg())
                .build();
    }

    private Long getSellerUserIdByOrderId(Long orderId) {
        return mapper.getSellerUserIdByOrderId(orderId);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public String subOrderAutoSigned(Long id) {
        // check子订单是否存在
        BizSubPhysicalOrder subOrder = bizSubPhysicalOrderService.getById(id);
        if (subOrder == null || subOrder.getDelFlag() == 1) {
            return null;
        }
        // check订单状态是否为已发货
        if (subOrder.getOrderStatus() != 3) {
            return null;
        }
        // 修改子订单状态
        LocalDateTime now = DateUtil.nowLdt();
        subOrder.setOrderStatus(4);
        subOrder.setSignedTime(now);
        subOrder.setUpdateTime(now);
        bizSubPhysicalOrderService.updateById(subOrder);

        // 发送送消息给卖家提示买家已签收订单
        Map<String, String> bizData = new HashMap<>();
        Long sellerUserId = this.getSellerUserIdByOrderId(subOrder.getOrderId());
        Map<String, Object> sellerOpenId = userClient.getOpenIdByUserId(sellerUserId);
        String openId = MapUtils.getString(sellerOpenId, "openId");
        bizData.put("openId", openId);
        String subOrderId = String.valueOf(subOrder.getId());
        bizData.put("orderId", subOrderId);

        bizData.put("buyer", "买家");
        String spuName = MapUtils.getString(subOrder.getSkuSnapshot(), "skuTitle");
        bizData.put("spuName", spuName);

        String title = "确认收货通知";
        String content = String.format("订单编号%s，用户已确认收货。", subOrderId);
        sysMsgProvider.sendSysMessage(1, 9003, bizData, sellerUserId, title, content, 0L);
        // end发送送消息给卖家提示买家已签收订单

        return "autoSigned suborder " + subOrderId;
    }

    @Override
    public List<Map<String, Object>> getOrderByConditions(Integer searchBy, String title, Integer busiType, Integer markCode, Integer orderType, Integer orderStatus, String startTime, String endTime, Page page) {
        LocalDateTime sTime = null;
        LocalDateTime eTime = null;
        if (!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
            sTime = LocalDateTime.of(DateUtil.parseLd(startTime, "yyyy-MM-dd"), LocalTime.MIN);
            eTime = LocalDateTime.of(DateUtil.parseLd(endTime, "yyyy-MM-dd"), LocalTime.MAX);
        }
        List<Map<String, Object>> result = mapper.getOrderByConditions(searchBy, title, busiType, markCode, orderType,
                orderStatus, sTime, eTime, page);
        result.forEach(m -> {
            // 订单状态
            Integer os = MapUtils.getInteger(m, "orderStatus");
            String strOrderStatus = "";
            switch (os) {
                case 1:
                    strOrderStatus = "待付款";
                    break;
                case 2:
                    strOrderStatus = "待发货";
                    break;
                case 3:
                    strOrderStatus = "待收货";
                    break;
                case 4:
                    if (StringUtils.isEmpty(MapUtils.getString(m, "ratingId"))) {
                        strOrderStatus = "待评价";
                    } else {
                        m.put("orderStatus", 6);
                        strOrderStatus = "已评价";
                    }
                    break;
                case 5:
                    strOrderStatus = "已关闭";
                    break;
                case 6:
                case 7:
                    m.put("orderStatus", 7);
                    strOrderStatus = "发货超时退款";
                    break;
                default:
            }
            m.put("orderStatusStr", strOrderStatus);

//            if (os.equals(4)) {
//                Long ratingId = MapUtils.getLong(m, "ratingId");
//                if (ratingId != null && ratingId != 0)
//                    m.put("orderStatus", 6);
//            } else if (os.intValue() == 6 || os.intValue() == 7) {
//                m.put("orderStatus", 7);
//            }
            // 销售类型
            Integer ot = MapUtils.getInteger(m, "orderType");
            switch (ot) {
                case 1:
                    m.put("orderTypeStr", "零售");
                    break;
                case 2:
                    m.put("orderTypeStr", "批采");
                    break;
                default:
            }
            // 购买用户类型
            Integer bt = MapUtils.getInteger(m, "shopType");
            String userType = "";
            switch (bt) {
                case 1:
                    userType = "普通用户";
                    break;
                case 2:
                    userType = "种植/养殖户";
                    break;
                case 3:
                    userType = "分拣厂合作社";
                    break;
                case 4:
                    userType = "物流/农资";
                    break;
                case 5:
                    userType = "包装物厂";
                    break;
                case 6:
                    userType = "超市采购商";
                    break;
                default:

            }
            m.put("userType", userType);
        });
        return result;
    }

    @Override
    public Map<String, Object> getOrderDetailById(Long id) {
        return mapper.getOrderDetailById(id);
    }

    @Override
    public JsonResult getSameSubOrderByOrderId(Long id, Long subId) {
        List<Map<String, Object>> entityList = mapper.getSameSubOrderByOrderId(id, subId);
        Map<String, Object> resultMap = new HashMap<>();
        List<String> skuNameList = new ArrayList<>();
        for (Map<String, Object> entityMap : entityList) {
            String skuSnapshot = MapUtils.getString(entityMap, "SkuSnapshot");
            Map<String, Object> skuMap = JsonUtil.jsonToMap(skuSnapshot);
            skuNameList.add(MapUtils.getString(skuMap, "skuTitle"));
            if (!resultMap.containsKey("amount")) {
                resultMap.put("amount", MapUtils.getInteger(entityMap, "RealAmount"));
            }
        }
        resultMap.put("skuTitles", Joiner.on("、").join(skuNameList));
        return JsonResult.success()
                .data(resultMap)
                .build();
    }

    @Override
    public List<Map<String, Object>> getSubOrdersByBusiId(Long busiId, Page page) {
        return mapper.getSubOrdersByBusiId(busiId, page);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void handleOrderTimeout(Long orderId) {
//        for (Long orderId : orderIdList) {
        // 获取订单，如果订单已支付则不处理
        BizPhysicalOrder orderEntity = mapper.selectById(orderId);
        if (orderEntity.getOrderStatus() == 1) {
            // 未支付订单
            orderEntity.setOrderStatus(5);
            orderEntity.setUpdateTime(DateUtil.nowLdt());
            mapper.updateById(orderEntity);
            // 逻辑删除主订单和所有子订单
            UpdateWrapper<BizSubPhysicalOrder> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("OrderId", orderId);
            BizSubPhysicalOrder subOrderEntity = new BizSubPhysicalOrder();
            subOrderEntity.setOrderStatus(5);
            subOrderEntity.setUpdateTime(DateUtil.nowLdt());
            bizSubPhysicalOrderService.update(subOrderEntity, updateWrapper);
        }
//        }
//        log.info("系统删除超时订单：[{}]", Joiner.on(",").join(orderIdList));
    }

    @Override
    public List<Long> getTimeoutOrder(int limit, int minutes) {
        return mapper.getTimeoutOrder(limit, minutes);
    }

    @Override
    public List<Map<String, Object>> getTradingsByConditions(Integer searchBy, String title, Integer orderType, Integer sellerType, Integer buyerType, Page page) {
        return mapper.getTradingsByConditions(searchBy, title, orderType, sellerType, buyerType, page);
    }

    @Override
    public List<Map<String, Object>> getOrderComplaintsByConditions(Integer searchBy, String title, Integer busiType, Integer markCode, Integer orderType, Integer orderStatus, String startTime, String endTime, Page page) {
        LocalDateTime sTime = null;
        LocalDateTime eTime = null;
        if (!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
            sTime = LocalDateTime.of(DateUtil.parseLd(startTime, "yyyy-MM-dd"), LocalTime.MIN);
            eTime = LocalDateTime.of(DateUtil.parseLd(endTime, "yyyy-MM-dd"), LocalTime.MAX);
        }
        return mapper.getOrderComplaintsByConditions(searchBy, title, busiType, markCode, orderType, orderStatus, sTime, eTime, page);
    }

    @Override
    public List<Map<String, Object>> getLongTimeUndeliveredOrders(Integer remindTime) {
        return mapper.getLongTimeUndeliveredOrders(remindTime);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void setOrderStatus(Long orderId, Integer orderStatus, Long paymentId, Integer orderType) {

        if (orderType == 2) {
            // 实物订单
            BizPhysicalOrder physicalOrder = this.getOne(new QueryWrapper<BizPhysicalOrder>()
                    .eq("Id", orderId)
                    .eq("OrderStatus", 1));

            if (physicalOrder != null) {
                // 实物订单
                // 更新父订单
                physicalOrder.setOrderStatus(orderStatus);
                LocalDateTime now = DateUtil.nowLdt();
                physicalOrder.setPaidTime(now);
                physicalOrder.setUpdateTime(now);
                physicalOrder.setPaymentId(paymentId);
                this.updateById(physicalOrder);

                // 更新子订单
                BizSubPhysicalOrder subPhysicalOrder = bizSubPhysicalOrderService.getOne(new QueryWrapper<BizSubPhysicalOrder>()
                        .eq("OrderId", orderId));
                subPhysicalOrder.setOrderStatus(orderStatus);
                subPhysicalOrder.setUpdateTime(now);
                bizSubPhysicalOrderService.updateById(subPhysicalOrder);

                // 买家支付成功后，给卖家发送新订单通知
                Long busiId = physicalOrder.getShopId();
                Integer busiType = physicalOrder.getShopType();
                Long shopUserId = infoBusinessService.getUserIdByBusiIdBusiType(busiId, busiType);
                Map<String, String> bizData = new HashMap<>();
                Map<String, Object> openId = userClient.getOpenIdByUserId(shopUserId);
                String shopOpenId = MapUtils.getString(openId, "openId");

                String title = "新订单提醒";
                String buyerName = physicalOrder.getBuyerShopName();
                String spuName = MapUtils.getString(subPhysicalOrder.getSkuSnapshot(), "skuTitle");
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                String orderTime = physicalOrder.getPaidTime().format(formatter);
                String deliDeadLine = physicalOrder.getPaidTime().plusHours(24).format(formatter);
                String content = String.format("用户%s向您购买%s，下单时间%s，请务必在%s前发货。", buyerName, spuName, orderTime, deliDeadLine);
                bizData.put("openId", shopOpenId);
                bizData.put("amount", String.valueOf(physicalOrder.getAmount().doubleValue() / 100));
                bizData.put("spuName", spuName);
                bizData.put("date", orderTime);
                bizData.put("orderId", subPhysicalOrder.getId().toString());
                bizData.put("remark", "请务必在24小时内完成发货");
                sysMsgProvider.sendSysMessage(1, 9001, bizData, shopUserId, title, content, 0L);

                // 延时19小时，给卖家发送催促发货提醒
                Long delay = remindTime * 3600L;
                String rTitle = "发货提醒";
                String rContent = String.format("用户%s向您购买%s，下单时间%s，距离发货时限已不足5小时，请及时发货，若已发货，请忽略此提醒。", buyerName, spuName, orderTime);
                sysMsgProvider.sendSysMessage(1, 9002, bizData, shopUserId, rTitle, rContent, delay);
                return;
            }
        } else if (orderType == 1) {
            // 虚拟订单
            BizServOrder servOrder = bizServOrderService.getOne(new QueryWrapper<BizServOrder>()
                    .eq("Id", orderId)
                    .eq("OrderStatus", 1));

            if (servOrder != null) {
                // 若是服务订单
                servOrder.setOrderStatus(2);
                servOrder.setPaymentId(paymentId);
                servOrder.setUpdateTime(DateUtil.nowLdt());
                bizServOrderService.updateById(servOrder);
                // 更新服务子订单
                List<BizSubServOrder> subServOrders = bizSubServOrderService.list(new QueryWrapper<BizSubServOrder>()
                        .eq("OrderId", orderId)
                        .eq("OrderStatus", 1));
                subServOrders.forEach(so -> {
                    so.setOrderStatus(2);
                    so.setUpdateTime(DateUtil.nowLdt());
                    bizSubServOrderService.updateById(so);
                });

                if (servOrder.getOrderType() == 1) {
                    // 保证金 更新保证金记录
                    BizDepositOperateRecord record = bizDepositOperateRecordService.list(new QueryWrapper<BizDepositOperateRecord>()
                            .eq("UserId", servOrder.getUserId()).orderByDesc("CreateTime")).get(0);
                    record.setOptType(2);
                    bizDepositOperateRecordService.updateById(record);
                    // 更新商铺表保证金状态
                    Long busiId = record.getBusiId();
                    Integer busiType = record.getBusiType();
                    switch (busiType) {
                        case 2:
                            infoFarmerService.update(new UpdateWrapper<InfoFarmer>()
                                    .eq("Id", busiId)
                                    .set("DepoStatus", 1)
                                    .set("Deposit", servOrder.getAmount())
                                    .set("DepoPaymTime", DateUtil.nowLdt()));
                            break;
                        case 3:
                        case 4:
                        case 5:
                            infoBusinessService.update(new UpdateWrapper<InfoBusiness>()
                                    .eq("Id", busiId)
                                    .set("DepoStatus", 1).set("Deposit", servOrder.getAmount())
                                    .set("DepoPaymTime", DateUtil.nowLdt()));
                            break;
                        default:
                            break;
                    }

                } else if (servOrder.getOrderType() == 3) {
                    Long userId = servOrder.getUserId();
                    // 礼物购买，把本次购买礼物加给用户
                    List<Map<String, Object>> boughtGifts = new ArrayList<>();
                    subServOrders.forEach(so -> {
                        Map<String, Object> gift = new HashMap<>();
                        gift.put("userId", userId);
                        gift.put("giftId", so.getServId());
                        gift.put("num", so.getNum());
                        boughtGifts.add(gift);
                    });
                    int code = activityClient.putUserGifts(boughtGifts, orderId);
                    if (code != 0)
                        throw new BizException(null, null);

                } else if (servOrder.getOrderType() == 2) {
                    // 租金，暂时无此业务需求
                }
            } else {
                // 在礼物购买情况下，很大可能是购买成功回调设置订单状态，这种情况下paymentId未写入，需处理paymentId未写入问题
                servOrder = bizServOrderService.getOne(new QueryWrapper<BizServOrder>()
                        .eq("Id", orderId)
                        .eq("OrderStatus", 2)
                        .isNull("PaymentId"));
                if (servOrder != null) {
                    servOrder.setPaymentId(paymentId);
                    bizServOrderService.updateById(servOrder);
                }
            }
        }
    }

    @Override
    public List<Map<String, Object>> getOrdersToDivide(int limit, int minutes) {
        return mapper.getOrdersToDivide(limit, minutes);
    }

    /**
     * so.OrderId as orderId,
     * so.Id as subOrderId,
     * o.OrderType as orderType,
     * o.ShopType as shopType,
     * so.RealAmount as totalAmount,
     * reg.UserCode as userCode,
     * reg.CustName as custName
     *
     * @param ordersToDivide
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void writePhyDistributionInfo(List<Map<String, Object>> ordersToDivide) {
        // 区分已完成订单 和 未发货退款订单
        List<Long> finishedSubOrderIds = ordersToDivide
                .stream()
                .filter(so -> MapUtils.getInteger(so, "orderStatus") == 4)
                .map(so -> MapUtils.getLong(so, "subOrderId"))
                .collect(Collectors.toList());
        List<Long> autoRefundSubOrderIds = ordersToDivide
                .stream()
                .filter(so -> MapUtils.getInteger(so, "orderStatus") == 6)
                .map(so -> MapUtils.getLong(so, "subOrderId"))
                .collect(Collectors.toList());
        // 已完成订单，只需更新分账状态为1
        if (finishedSubOrderIds.size() > 0)
            bizSubPhysicalOrderService.update(new UpdateWrapper<BizSubPhysicalOrder>()
                    .in("Id", finishedSubOrderIds)
                    .eq("OrderStatus", 4)
                    .set("DistStatus", 1));
        // 未发货自动退款订单，更新分账状态为1 后还需更新订单状态为未发货已退款为7
        if (autoRefundSubOrderIds.size() > 0)
            bizSubPhysicalOrderService.update(new UpdateWrapper<BizSubPhysicalOrder>()
                    .in("Id", autoRefundSubOrderIds)
                    .eq("OrderStatus", 6)
                    .set("DistStatus", 1)
                    .set("OrderStatus", 7));

        int result = paidClient.writePhyDistributionInfoBatch(ordersToDivide);
        if (result != 0)
            throw new BizException(null, null);
    }

    @Override
    public void writeServDistributionInfo(List<Map<String, Object>> ordersToDivide) {
        List<Long> finishedOrderIds = ordersToDivide
                .stream()
                .map(so -> MapUtils.getLong(so, "orderId"))
                .collect(Collectors.toList());

        bizServOrderService.update(new UpdateWrapper<BizServOrder>()
                .in("Id", finishedOrderIds)
                .eq("OrderStatus", 2)
                .eq("DistStatus", 0)
                .set("DistStatus", 1));

        int result = paidClient.writeServDistributionInfoBatch(ordersToDivide);
        if (result != 1)
            throw new BizException(null, null);
    }

    @Override
    public List<Long> getLongTimeUnsignedSubOrders(int limit) {
        List<Long> result = mapper.getLongTimeUnsignedSubOrders(limit, autoSignDays);
        return result;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public String doAutoRefund(Map<String, Object> so) {
        Long orderId = MapUtils.getLong(so, "orderId");
        Long subOrderId = MapUtils.getLong(so, "subOrderId");
        Integer amount = MapUtils.getInteger(so, "amount");
        String refundAmount = String.valueOf(amount.doubleValue() / 100);
        // 登记退款表
        int code = paidClient.refund(4004L, orderId, subOrderId, refundAmount);
        if (code != 0)
            throw new BizException(null, null);

        // 更新子订单状态为待退款，分账信息生成任务会扫描到该条
        bizSubPhysicalOrderService.update(new UpdateWrapper<BizSubPhysicalOrder>()
                .eq("Id", subOrderId)
                .eq("OrderStatus", 2)
                .set("OrderStatus", 6));
        String log = "子订单 " + subOrderId + " 商家逾期未发货，已自动退款\n";
        return log;
    }

    @Override
    public List<Map<String, Object>> getAutoRefundSubOrders(int limit) {
        List<Map<String, Object>> result = mapper.getAutoRefundSubOrders(limit, autoRefundHours);
        return result;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public String handleYsDeliver(Map<String, Object> orderInfo) {
        Long orderId = MapUtils.getLong(orderInfo, "orderId");
        Long paymentId = MapUtils.getLong(orderInfo, "paymentId");

        BizPhysicalOrder order = new BizPhysicalOrder();
        order.setId(orderId);
        order.setGuaranteeStatus(1);
        this.updateById(order);

        int code = paidClient.ysDelivery(paymentId);
        if (code != 1) {
            throw new BizException(null, null);
        }
        return "handleYsDeliver order " + orderId;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public String handleYsSign(Map<String, Object> orderInfo) {
        Long orderId = MapUtils.getLong(orderInfo, "orderId");
        Long paymentId = MapUtils.getLong(orderInfo, "paymentId");

        BizPhysicalOrder order = new BizPhysicalOrder();
        order.setId(orderId);
        order.setGuaranteeStatus(2);
        this.updateById(order);

        int code = paidClient.ysSign(paymentId);
        if (code != 1) {
            throw new BizException(null, null);
        }
        return "handleYsSign order " + orderId;
    }

    @Override
    public List<Map<String, Object>> getServOrdersToDivide(int limit, int minutes) {
        return bizServOrderService.getServOrdersToDivide(limit);
    }

    @Override
    public RpcReturnPage<Map<String, Object>> getOrderForBreakfast(Page page, Long shopId, Long subOrderId, Integer busiType,
                                                                   Integer orderType, Integer orderStatus, LocalDateTime startTime,
                                                                   LocalDateTime endTime) {
        Page<Map<String, Object>> returnPage = mapper.getOrderForBreakfast(page, shopId, subOrderId, busiType,
                orderType, orderStatus, startTime, endTime);
        List<Map<String, Object>> viewList = new ArrayList<>();
        Map<String, Object> tmpMap;
        for (Map<String, Object> recordMap : returnPage.getRecords()) {
            tmpMap = new HashMap<>();
            Map<String, Object> receiveInfoMap = JsonUtil.jsonToMap(MapUtils.getString(recordMap, "receiveInfo", "{}"));
            Map<String, Object> skuSnapshotMap = JsonUtil.jsonToMap(MapUtils.getString(recordMap, "skuSnapshot", "{}"));
            tmpMap.putAll(recordMap);
            tmpMap.remove("receiveInfo");
            tmpMap.remove("skuSnapshot");
            tmpMap.put("skuTitle", MapUtils.getString(skuSnapshotMap, "skuTitle"));
            tmpMap.putAll(receiveInfoMap);
            // 订单状态
            Integer os = MapUtils.getInteger(recordMap, "orderStatus");
            String strOrderStatus = "";
            switch (os) {
                case 1:
                    strOrderStatus = "待付款";
                    break;
                case 2:
                    strOrderStatus = "待发货";
                    break;
                case 3:
                    strOrderStatus = "待收货";
                    break;
                case 4:
                    if (StringUtils.isEmpty(MapUtils.getString(recordMap, "ratingId"))) {
                        strOrderStatus = "待评价";
                    } else {
                        tmpMap.put("orderStatus", 6);
                        strOrderStatus = "已评价";
                    }
                    break;
                case 5:
                    strOrderStatus = "已关闭";
                    break;
                case 6:
                case 7:
                    tmpMap.put("orderStatus", 7);
                    strOrderStatus = "发货超时退款";
                    break;
                default:
            }
            tmpMap.put("orderStatusStr", strOrderStatus);
            // 销售类型
            Integer ot = MapUtils.getInteger(recordMap, "orderType");
            switch (ot) {
                case 1:
                    tmpMap.put("orderTypeStr", "零售");
                    break;
                case 2:
                    tmpMap.put("orderTypeStr", "批采");
                    break;
                default:
            }
            viewList.add(tmpMap);
        }
        RpcReturnPage<Map<String, Object>> rpcReturnPage = new RpcReturnPage<>();
        rpcReturnPage.setDataList(viewList);
        rpcReturnPage.setTotal(returnPage.getTotal());
        return rpcReturnPage;
    }

    @Override
    public List<BreakfastExcel> getOrderForBreakfastExcel(Long shopId, Integer busiType, LocalDateTime startTime,
                                                          LocalDateTime endTime) {
        List<Map<String, Object>> dataList = mapper.getOrderForBreakfastExcel(shopId, busiType, startTime, endTime);
        List<BreakfastExcel> viewList = new ArrayList<>();
        int i = 1;
        for (Map<String, Object> dataMap : dataList) {
            BreakfastExcel view = new BreakfastExcel();
            Map<String, Object> receiveInfoMap = JsonUtil.jsonToMap(MapUtils.getString(dataMap, "receiveInfo", "{}"));
            Map<String, Object> skuSnapshotMap = JsonUtil.jsonToMap(MapUtils.getString(dataMap, "skuSnapshot", "{}"));
            view.setNo("" + i++);
            view.setOrderNumber(MapUtils.getString(dataMap, "id"));
            view.setNum(MapUtils.getString(dataMap, "num"));
            view.setPaidDate(MapUtils.getString(dataMap, "paidTime"));
            view.setSkuTitle(MapUtils.getString(skuSnapshotMap, "skuTitle"));
            view.setContact(MapUtils.getString(receiveInfoMap, "contact"));
            view.setPhone(MapUtils.getString(receiveInfoMap, "phone"));
            view.setAddress(MapUtils.getString(receiveInfoMap, "address"));
            viewList.add(view);
        }
        return viewList;
    }


}
